Mythril and Slither are two widely-used tools in the Ethereum security ecosystem, designed to identify vulnerabilities and risks in smart contracts. They provide different approaches to static and dynamic analysis, each having strengths in particular areas of contract auditing.
Mythril is a security analysis tool specifically built for detecting vulnerabilities in Ethereum smart contracts. It operates by executing symbolic execution, SMT (Satisfiability Modulo Theories) solving, and taint analysis. Mythril can identify a wide variety of common Solidity vulnerabilities, with customizable modules allowing for detailed and flexible analysis.
Each module specializes in identifying specific vulnerabilities in smart contracts:
Delegate Call To Untrusted Contract: Detects cases where contracts use delegate calls to untrusted contracts, which can result in loss of control.
Dependence on Predictable Variables: Identifies reliance on easily predictable variables (e.g., block.timestamp or blockhash).
Ether Thief: Detects situations where the contract can send Ether to arbitrary accounts.
Exceptions: Identifies incorrect handling of exceptions, which can break contract logic.
External Calls: Detects unsafe external contract calls, which could lead to reentrancy or other attacks.
Integer: Finds integer overflow and underflow issues, potentially leading to erroneous calculations or contract behavior.
Multiple Sends: Detects contracts that send Ether to multiple accounts, potentially exposing them to denial of service (DoS) risks.
Suicide: Finds vulnerabilities where unauthorized users can trigger the self-destruct function.
State Change External Calls: Detects situations where external calls are made after state changes, leading to reentrancy vulnerabilities.
Unchecked Retval: Identifies cases where return values of critical functions are not checked, leading to logic errors.
User-Supplied Assertion: Detects contracts using user-supplied data in assertions, which can be manipulated to crash the contract.
Arbitrary Storage Write: Finds vulnerabilities where unauthorized users can write to arbitrary storage locations.
Arbitrary Jump: Detects when arbitrary jumps are possible, leading to unpredictable behavior.
A developer wants to check for integer overflow vulnerabilities in their smart contract that deals with token transfers. Mythril’s Integer module can detect this issue through symbolic execution and ensure that safe math is implemented properly.
Slither is a static analysis tool for Solidity that provides a faster, more lightweight alternative to symbolic execution tools. It offers high confidence results on various Solidity patterns, identifying vulnerabilities that can affect the contract’s functionality, security, and efficiency.
Slither has a broader range of detectors organized into categories by impact and confidence. Below are some detectors and what they reveal:
| Num | Detector | What It Detects | Impact | Confidence |
|---|---|---|---|---|
| 1 | abiencoderv2-array | Storage ABIEncoderV2 array | High | High |
| 2 | arbitrary-send-erc20 | Detects arbitrary transferFrom ERC20 calls |
High | High |
| 12 | suicidal | Functions that allow anyone to self-destruct the contract | High | High |
| 13 | uninitialized-state | Uninitialized state variables, which can lead to undefined behavior | High | High |
| 25 | reentrancy-eth | Reentrancy vulnerabilities that lead to Ether theft | High | Medium |
| 29 | weak-prng | Weak pseudorandom number generation, which can be exploited | High | Medium |
| 48 | tx-origin | Dangerous usage of tx.origin, making contracts vulnerable to phishing attacks |
Medium | Medium |
| 51 | uninitialized-local | Uninitialized local variables that may lead to unexpected behavior | Medium | Medium |
| 89 | cache-array-length | Detects inefficient loops that use array.length repeatedly in loop conditions |
Optimization | High |
| 92 | immutable-states | Identifies state variables that could be declared immutable to save gas |
Optimization | High |
A developer is concerned about reentrancy vulnerabilities in their Ethereum contract, particularly in functions that handle Ether transfers. Using Slither’s reentrancy-eth detector, they can efficiently identify unsafe patterns such as external calls made before internal state changes, which are prime targets for reentrancy attacks.
| Tool | Best for | Strengths | Weaknesses |
|---|---|---|---|
| Mythril | - Complex analysis where symbolic execution is needed - Verifying contract behavior under specific conditions |
- Symbolic execution allows for detailed coverage of potential contract states - Can detect deep vulnerabilities like integer overflow, unchecked retval, etc. |
- Slower due to the depth of analysis - May generate false positives due to over-analysis |
| Slither | - Quick detection of common Solidity anti-patterns - Optimizing contract for gas efficiency |
- Very fast, works on static code - Focused on Solidity-specific issues - High accuracy with confidence indicators |
- Lacks deep symbolic analysis - Doesn’t explore possible execution states |
Creating a custom Slither module (also called a detector) allows you to extend Slither’s analysis capabilities and identify specific patterns or vulnerabilities in your smart contracts. In this example, we will create a custom Slither detector that identifies contracts using low-level call() without checking the return value—a common mistake that could lead to security vulnerabilities, as the failure of the call might go unnoticed.
Here is a step-by-step guide to creating a custom Slither module.
First, make sure you have Slither installed. You can install it using pip:
pip install slither-analyzer
Next, create a directory structure for your custom module. For this example, let’s call the file custom_call_check.py.
In the file custom_call_check.py, define a new class that extends Slither’s Detector class. Slither provides various hooks and helpers to interact with Solidity contracts and functions.
from slither.core.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.slithir.operations import LowLevelCall
class CustomCallCheck(AbstractDetector):
"""
This detector identifies the use of low-level `call()` without checking the return value.
"""
ARGUMENT = 'call-without-check'
HELP = 'Detect low-level call without checking the return value'
IMPACT = DetectorClassification.HIGH
CONFIDENCE = DetectorClassification.HIGH
def _detect(self):
issues = []
# Iterate through each contract
for contract in self.compilation_unit.contracts:
# Iterate through each function in the contract
for function in contract.functions_and_modifiers:
# Iterate through the intermediate representation (IR) instructions of the function
for ir in function.slithir_operations:
# We are interested in low-level calls
if isinstance(ir, LowLevelCall):
# Check if the return value of the call is ignored (i.e., unused)
if not ir.result:
# Create a unique issue for each detected instance
issue_info = [
f"Function {function.name} in contract {contract.name} "
f"uses low-level call() without checking the return value."
]
issues.append(self.generate_result(issue_info))
return issues
Imports: We import Slither’s core AbstractDetector and necessary classes for analysis. LowLevelCall is a SlithIR (Slither Intermediate Representation) operation that corresponds to low-level Solidity calls like address.call().
Detector Class: We define a new class CustomCallCheck that extends AbstractDetector. This class holds the logic to detect our vulnerability of interest.
Detection Logic:
LowLevelCall operation and check whether the return value (ir.result) is ignored (not checked).Attributes:
ARGUMENT: This is the argument you’ll use to invoke this custom detector from the command line.IMPACT and CONFIDENCE: These classifications describe how severe the issue is and how confident the detector is in identifying real problems.To run this custom detector, you would first save the custom_call_check.py file in the proper directory under Slither’s detectors/ directory or provide it as a custom argument in your setup.
You can now invoke the custom detector like this:
slither . --detect call-without-check
This will run the Slither analysis and include your custom detector, scanning all contracts in the current directory (.) for low-level calls that do not check the return value.
Let’s test this detector with a simple vulnerable Solidity contract:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Vulnerable {
function sendEther(address payable recipient) public {
// Low-level call without checking the return value
recipient.call{value: 1 ether}("");
}
}
In this contract, the call() function is used to transfer Ether, but the return value is not checked. This can lead to unhandled failures, and the custom detector should flag it as a potential issue.
After running the custom detector, you should see output similar to the following:
INFO:Slither:Vulnerable uses low-level call() without checking the return value
Function sendEther in contract Vulnerable uses low-level call() without checking the return value.
This confirms that the custom detector works as expected, identifying contracts that fail to check return values from low-level calls.
Both Mythril and Slither serve as crucial tools in Ethereum smart contract development, helping developers identify and mitigate security vulnerabilities. Depending on the need—deep symbolic execution or fast, static code analysis—one tool may be more appropriate than the other.
By combining the strengths of both tools, developers can create more secure and efficient smart contracts on Ethereum.